/*
 * Copyright (c) 2015. For Intelligent Group.
 */

package com.intelligent.ispc.core.service.impl;

import com.google.common.collect.Lists;
import com.intelligent.ispc.common.mapper.BeanMapper;
import com.intelligent.ispc.common.persistence.DynamicSpecifications;
import com.intelligent.ispc.common.persistence.SearchFilter;
import com.intelligent.ispc.common.utils.ExceptionMessages;
import com.intelligent.ispc.core.dto.LogDto;
import com.intelligent.ispc.core.entity.Log;
import com.intelligent.ispc.core.repository.jpa.LogDao;
import com.intelligent.ispc.core.service.LogService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.List;
import java.util.Map;

/**
 * Created by Peter on 15/11/23.
 */
@Service
public class LogServiceImpl implements LogService {

    private Logger logger = LoggerFactory.getLogger(LogServiceImpl.class);

    @Autowired
    private LogDao logDao;

    @Override
    public void log(LogDto logDto) {
        if (logDto == null) {
            logger.error("Can not insert the log: {}", ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        Log entity = new Log();
        BeanMapper.copy(logDto, entity);

        logger.debug("Insert log:{}", logDto);
        logDao.save(entity);
        logger.info("Insert log done, log={}", logDto);
    }

    @Override
    public List<LogDto> searchLog(Map<String, Object> searchParams) {
        logger.debug("Searching user with {},{},{}", searchParams.keySet(), searchParams.values());

        Map<String, SearchFilter> filters = SearchFilter.parse(searchParams);
        Specification<Log> spec = DynamicSpecifications.bySearchFilter(filters.values(), Log.class);

        List<Log> logList = logDao.findAll(spec);
        logger.debug("Searching log, total elements:{}", logList.size());

        List<LogDto> logDtos = Lists.newArrayList();
        for (Log entity : logList) {
            LogDto dto = new LogDto();
            BeanMapper.copy(entity, dto);
            logDtos.add(dto);
        }

        return logDtos;
    }

    @Override
    public Page<LogDto> searchLog(Map<String, Object> searchParams, Pageable pageable) {
        logger.debug("Searching user with {},{},{}", searchParams.keySet(), searchParams.values(), pageable);

//        Map<String, SearchFilter> filters = SearchFilter.parse(searchParams);
//        Specification<Log> spec = DynamicSpecifications.bySearchFilter(filters.values(), Log.class);

        Specification<Log> spec = new Specification<Log>() {
            public Predicate toPredicate(Root<Log> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                List<Predicate> predicates = Lists.newArrayList();
                if (searchParams.get("content") != null) {
                    Predicate p = cb.like(root.get("content").as(String.class), "%" + searchParams.get("content").toString() + "%");
                    predicates.add(p);
                }
                if (searchParams.get("startTime") != null) {
                    Predicate p = cb.greaterThanOrEqualTo(root.get("createTime").as(String.class), searchParams.get("startTime").toString());
                    predicates.add(p);
                }
                if (searchParams.get("endTime") != null) {
                    Predicate p = cb.lessThanOrEqualTo(root.get("createTime").as(String.class), searchParams.get("endTime").toString());
                    predicates.add(p);
                }
                if (searchParams.get("operation") != null) {
                    Predicate p = cb.like(root.get("operation").as(String.class), "%" + searchParams.get("operation").toString() + "%");
                    predicates.add(p);
                }
                if (searchParams.get("actor") != null) {
                    Predicate p = cb.like(root.get("createBy").as(String.class), "%" + searchParams.get("actor").toString() + "%");
                    predicates.add(p);
                }

                if (!predicates.isEmpty()) {
                    query.where(cb.and(predicates.toArray(new Predicate[predicates.size()])));
                }

                return query.getRestriction();
            }
        };

        Sort sort = pageable.getSort();
        if (sort == null) {
            sort = new Sort(Sort.Direction.DESC, "createTime");
        } else {
            sort.and(new Sort(Sort.Direction.DESC, "createTime"));
        }

        Pageable p = new PageRequest(pageable.getPageNumber(), pageable.getPageSize(), sort);

        Page<Log> logPage = logDao.findAll(spec, p);
        logger.debug("Searching project, total elements:{}", logPage.getTotalElements());

        List<Log> logs = logPage.getContent();
        List<LogDto> logDtos = Lists.newArrayList();
        for (Log entity : logs) {
            LogDto dto = new LogDto();
            BeanMapper.copy(entity, dto);
            logDtos.add(dto);
        }

        Page<LogDto> pageDto = new PageImpl<LogDto>(logDtos, pageable, logPage.getTotalElements());

        return pageDto;
    }
}
